package service

import (
	"encoding/hex"
	"gitee.com/crack007/goose"
	"gitee.com/crack007/udp-penetrate/src/api/config"
	"gitee.com/crack007/udp-penetrate/src/common/constant"
	"gitee.com/crack007/udp-penetrate/src/common/dto"
	"gitee.com/crack007/udp-penetrate/src/common/exception"
	"gitee.com/crack007/udp-penetrate/src/common/protocol"
	"net"
)

type clientService struct {
	serverUdpConn *net.UDPConn
	clientUid     uint32
	clientConn    *net.UDPConn
}

func (s *clientService) CheckIn(userDto *dto.UserDto) (resp interface{}) {
	s.clientUid = userDto.Uid
	var err error
	defer func() {
		if err != nil {
			resp = exception.NewApiException(err.Error(), 500)
		}
	}()
	s.serverUdpConn, err = net.DialUDP("udp", &net.UDPAddr{Port: int(config.ArgConfig.LocalPort)}, &net.UDPAddr{IP: net.ParseIP(config.AppConfig.ServerHost), Port: int(config.AppConfig.ServerPort)})
	if err != nil {
		return err
	}
	go func() {
		var err error
		defer func() {
			if err != nil {
				panic(err)
			}
		}()
		var respBody = make([]byte, 0xffff)
		for {
			n, err := s.serverUdpConn.Read(respBody)
			if err != nil {
				return
			}
			goose.GetLogger().Debug("\r\n%s", hex.Dump(respBody[:n]))
			iProtocol, err := protocol.UnpackData(respBody[:n])
			if err != nil {
				return
			}
			if iProtocol.Code() == constant.CMD_CLIENTHANDSHAKE_REQ || iProtocol.Code() == constant.CMD_CTOCHANDSHAKE_REQ {
				s.serverUdpConn.Close()
				if v, ok := iProtocol.(*protocol.CtoCHandshakeReqProtocol); ok {
					// 准备和目标客户端创建连接
					s.clientConn, err = net.DialUDP("udp", &net.UDPAddr{Port: int(config.ArgConfig.LocalPort)}, &net.UDPAddr{
						IP:   net.ParseIP(v.TargetHost),
						Port: int(v.TargetPort),
					})
				}
			}
			iProtocol.Process(nil, s.clientConn)
		}
	}()
	handshakeReqProtocol := protocol.NewHandshakeReqProtocol()
	handshakeReqProtocol.Uid = userDto.Uid
	packData, err := protocol.PackData(handshakeReqProtocol)
	if err != nil {
		return nil
	}
	_, err = s.serverUdpConn.Write(packData)
	if err != nil {
		return nil
	}
	return
}

// 和目标用户建立连接
func (s *clientService) Connect(uid uint32) interface{} {
	// 通知server
	connectReqProtocol := protocol.NewConnectReqProtocol()
	connectReqProtocol.TargetUid = uid
	connectReqProtocol.OriginUid = s.clientUid
	packData, err := protocol.PackData(connectReqProtocol)
	if err != nil {
		return exception.NewApiException(err.Error(), 500)
	}
	_, err = s.serverUdpConn.Write(packData)
	if err != nil {
		return exception.NewApiException(err.Error(), 500)
	}
	return nil
}

// 发送消息
func (s *clientService) SendMsg(messageDto *dto.MessageDto) interface{} {

	connectReqProtocol := protocol.NewMessageProtocol()
	connectReqProtocol.Msg = messageDto.Msg

	packData, err := protocol.PackData(connectReqProtocol)
	if err != nil {
		return exception.NewApiException(err.Error(), 500)
	}
	_, err = s.clientConn.Write(packData)
	if err != nil {
		return exception.NewApiException(err.Error(), 500)
	}
	return nil
}
